<script setup lang="ts">
  import { useTypingStore } from '@renderer/store'
  import { ref, onMounted, nextTick, watch } from 'vue'

  const typingStore = useTypingStore()

  // 状态变量
  const inputRefs = ref<HTMLInputElement[]>([])
  const wordRefs = ref<HTMLElement[]>([])
  const ignoreNextInput = ref(false)
  const prevInputValues = ref<string[]>([])

  // 初始化词语列表
  const initializeWords = () => {
    typingStore.initWords()
    prevInputValues.value = Array(typingStore.words.length).fill('')
    nextTick(() => {
      focusInput(0)
    })
  }

  // 判断词的输入是否有错误
  const hasError = (index: number) => {
    if (index < 0 || index >= typingStore.inputs.length) {
      return false
    }

    const input = typingStore.inputs[index]
    const word = typingStore.words[index]

    if (input.length === 0 && index < typingStore.currentIndex) {
      return true
    }

    if (input.length !== word.length && index < typingStore.currentIndex) {
      return true
    }

    for (let i = 0; i < input.length; i++) {
      if (input[i] !== word[i]) {
        return true
      }
    }

    return false
  }

  // 计算单个词的错误字符数
  const countWordErrors = (index: number) => {
    const input = typingStore.inputs[index] || ''
    const word = typingStore.words[index] || ''
    let errorCount = 0

    for (let i = 0; i < Math.min(input.length, word.length); i++) {
      if (input[i] !== word[i]) {
        errorCount++
      }
    }

    if (index < typingStore.currentIndex && input.length < word.length) {
      errorCount += word.length - input.length
    }

    if (input.length > word.length) {
      errorCount += input.length - word.length
    }

    return errorCount
  }

  // 计算所有已输入词的错误总数
  const calculateTotalErrors = () => {
    let totalErrors = 0
    for (let i = 0; i <= typingStore.currentIndex; i++) {
      if (i < typingStore.inputs.length) {
        totalErrors += countWordErrors(i)
      }
    }
    return totalErrors
  }

  // 检查输入变化是否包含错误
  const checkForErrors = (index: number, newValue: string) => {
    const prevValue = prevInputValues.value[index] || ''
    const expectedWord = typingStore.words[index]

    if (newValue.length > prevValue.length) {
      const lastChar = newValue[newValue.length - 1]
      const expectedChar = expectedWord[newValue.length - 1]

      if (
        newValue.length > expectedWord.length ||
        (expectedChar !== undefined && lastChar !== expectedChar)
      ) {
        typingStore.incrementTotalErrorCount()
      }
    }

    prevInputValues.value[index] = newValue
  }

  // 设置是否忽略下一次输入
  const setIgnoreNextInput = (value: boolean) => {
    ignoreNextInput.value = value
  }

  // 处理输入
  const handleInput = (index: number, e: Event) => {
    if (ignoreNextInput.value) {
      ignoreNextInput.value = false
      return
    }

    typingStore.startTimer()

    if (index === typingStore.currentIndex) {
      const input = e.target as HTMLInputElement
      const newValue = input.value

      checkForErrors(index, newValue)
      typingStore.inputs[index] = newValue

      typingStore.totalTypedChars = 0
      for (let i = 0; i <= typingStore.currentIndex; i++) {
        if (typingStore.inputs[i]) {
          typingStore.totalTypedChars += typingStore.inputs[i].length
        }
      }

      typingStore.totalErrorChars = calculateTotalErrors()
    }
  }

  // 处理按键
  const handleKeyDown = (index: number, e: KeyboardEvent) => {
    if (index !== typingStore.currentIndex || typingStore.isPaused) {
      e.preventDefault()
      return
    }

    if (e.key === ' ' || e.code === 'Space') {
      e.preventDefault()

      if (index < typingStore.words.length - 1 && typingStore.inputs[index].length > 0) {
        typingStore.currentIndex = index + 1
        focusInput(index + 1)
      } else if (index === typingStore.words.length - 1) {
        typingStore.completed()
      }
    } else if (e.key === 'Backspace') {
      if (typingStore.inputs[index].length === 0 && index > 0) {
        const prevWordIndex = index - 1
        const prevWordHasError = prevWordIndex >= 0 && hasError(prevWordIndex)
        if (prevWordHasError) {
          typingStore.currentIndex = prevWordIndex
          focusInput(prevWordIndex)
          e.preventDefault()
          return
        }
      }
    }
  }

  // 阻止点击选择输入框
  const handleFocus = (index: number, e: FocusEvent) => {
    if (index !== typingStore.currentIndex) {
      e.preventDefault()
      e.stopPropagation()
      focusInput(typingStore.currentIndex)
    }
  }

  // 阻止鼠标滚动
  const handleWheel = (e: WheelEvent) => {
    e.preventDefault()
  }

  // 获取字符样式
  const getCharClass = (wordIndex: number, charIndex: number) => {
    const input = typingStore.inputs[wordIndex]
    const wordLength = typingStore.words[wordIndex].length

    if (charIndex < input.length) {
      if (charIndex >= wordLength) {
        return 'text-red-400'
      }

      const expectedChar = typingStore.words[wordIndex][charIndex]
      const actualChar = input[charIndex]

      if (actualChar === expectedChar) {
        return 'dark:text-white text-black'
      } else {
        return 'text-red-400'
      }
    }

    return 'text-gray-400'
  }

  // 获取需要显示的字符
  const getDisplayChar = (wordIndex: number, charIndex: number) => {
    const word = typingStore.words[wordIndex]
    const input = typingStore.inputs[wordIndex] || ''
    const wordLength = word.length

    if (charIndex < wordLength) {
      return word[charIndex]
    } else if (charIndex >= wordLength && charIndex < input.length) {
      return input[charIndex]
    }

    return ''
  }

  // 获取要显示的字符数组
  const getDisplayChars = (wordIndex: number) => {
    const word = typingStore.words[wordIndex]
    const input = typingStore.inputs[wordIndex] || ''
    const displayLength = Math.max(word.length, input.length)
    return Array.from({ length: displayLength }, (_, i) => i)
  }

  // 聚焦输入框
  const focusInput = (index: number) => {
    nextTick(() => {
      if (inputRefs.value[index]) {
        inputRefs.value[index].focus()
      }
    })
  }

  // 设置引用
  const setInputRef = (el: HTMLInputElement, index: number) => {
    if (el) {
      inputRefs.value[index] = el
    }
  }

  // 设置词元素引用
  const setWordRef = (el: HTMLElement, index: number) => {
    if (el) {
      wordRefs.value[index] = el
    }
  }

  // 判断是否显示下划线
  const showUnderline = (wordIndex: number) => {
    return wordIndex === typingStore.currentIndex
  }

  // 监听当前索引变化
  watch(
    () => typingStore.currentIndex,
    () => {
      typingStore.totalErrorChars = calculateTotalErrors()
    }
  )

  // 向外暴露方法
  const focusCurrentInput = () => {
    focusInput(typingStore.currentIndex)
  }

  defineExpose({
    focusCurrentInput,
    setIgnoreNextInput
  })

  onMounted(() => {
    initializeWords()
  })
</script>

<template>
  <div class="flex flex-wrap gap-4 h-40">
    <div
      v-for="(_word, wordIndex) in typingStore.words"
      :key="wordIndex"
      class="inline-flex items-center relative"
      :ref="(el) => setWordRef(el as HTMLElement, wordIndex)"
    >
      <div
        class="flex flex-row relative"
        :class="{ 'border-b-2 border-indigo-400': showUnderline(wordIndex) }"
      >
        <span
          v-for="(_char, charIndex) in getDisplayChars(wordIndex)"
          :key="charIndex"
          class="text-2xl font-semibold tracking-normal font-mono"
          :class="getCharClass(wordIndex, charIndex)"
        >
          {{ getDisplayChar(wordIndex, charIndex) }}
        </span>

        <input
          :ref="(el) => setInputRef(el as HTMLInputElement, wordIndex)"
          type="text"
          class="outline-none border-none bg-transparent opacity-0 h-full w-full cursor-text select-none inset-0 absolute z-1"
          :class="{ 'rounded-md shadow-indigo': wordIndex === typingStore.currentIndex }"
          style="user-select: none; -webkit-user-drag: none"
          :value="typingStore.inputs[wordIndex] || ''"
          @input="handleInput(wordIndex, $event)"
          @keydown="handleKeyDown(wordIndex, $event)"
          @focus="handleFocus(wordIndex, $event)"
          @wheel="handleWheel"
        />
      </div>
      <span class="text-gray-400 mx-1"> </span>
    </div>
  </div>
</template>

<style lang="scss" scoped></style>
